<?php
/**
 * Created by PhpStorm.
 * User: meng
 * Date: 2023/9/15
 * Time: 14:29
 */

namespace app\service;

use Hidehalo\Nanoid\Client;
use lib\common\CommonService;
use lib\utils\CacheUtils;
use Webman\Captcha\CaptchaBuilder;
use Webman\Captcha\PhraseBuilder;

class CaptchaService extends CommonService
{
    const SCENE_ADMIN_LOGIN = 'admin_login';
    const CACHE_KEY = 'captcha';

    public function generate ($length = 4, $scene = self::SCENE_ADMIN_LOGIN): array {
        $client = make(Client::class);
        $token = $client->generateId(32);
        $phraseBuilder = new PhraseBuilder($length);
        $builder = new CaptchaBuilder(null, $phraseBuilder);
        $builder->setBackgroundColor(255, 255, 255)->build();
        $codeUrl = $builder->inline();
        $codeText = $builder->getPhrase();
        $this->setCache($token, ['code'  => $codeText, 'times' => 0], 300, $scene);
        return [
            'code' => $codeUrl,
            'token' => $token,
        ];
    }

    public function verify ($code, $token, $scene = self::SCENE_ADMIN_LOGIN): bool {
        // 缓存中获取验证码
        $captcha = $this->getCache($token, $scene);
        if (empty($captcha) || empty($captcha['code']) || !isset($captcha['times'])) {
            return false;
        }

        // 对比用户输入
        if (strtolower($captcha['code']) != strtolower($code)) {
            $captcha['times'] += 1;
            // 失败超过5次删除
            if ($captcha['times'] >= 5) {
                $this->removeCache($token, $scene);
            } else {
                $ttl = $this->getTtl($token, $scene);
                if ($ttl > 1) {
                    $this->setCache($token, $captcha, $ttl, $scene);
                }
            }
            return false;
        }

        // 验证成功删除
        $this->removeCache($token, $scene);
        return true;
    }

    private function getTtl ($token, $scene = self::SCENE_ADMIN_LOGIN): ?int {
        return CacheUtils::ttl(self::CACHE_KEY . ':' . $scene . ':' . $token);
    }
    private function removeCache ($token, $scene = self::SCENE_ADMIN_LOGIN) {
        CacheUtils::forget(self::CACHE_KEY . ':' . $scene . ':' . $token);
    }

    private function getCache ($token, $scene = self::SCENE_ADMIN_LOGIN) {
        return CacheUtils::get(self::CACHE_KEY . ':' . $scene . ':' . $token);
    }

    private function setCache ($token, $data, $ttl = 300, $scene = self::SCENE_ADMIN_LOGIN) {
        CacheUtils::put(self::CACHE_KEY . ':' . $scene . ':' . $token, $data, $ttl);
    }
}
